# -*- coding: utf-8 -*-
import nltk
import re
import sys
import cPickle
import math
from xml.dom.minidom import *

# Cargar los posibles problemas a resolver
from LProblemas import *

# Cargar objeto para representar al héroe
from problemas.heroe import Heroe

# Cargar elementos auxiliares
from problemas.acciones.ITener import ITener
from problemas.acciones.ITenerParticula import ITenerParticula
import sys

class Nodo:
    
    """
    Representa un Nodo en un arbol de parse. Contiene la informacion  necesaria para manejar eficientemente el analisis semantico.
    @since: 4/14/2011
    @version: 1.0
    """
    
    def __init__(self, tok, lex, ind):
        """
        Constructor
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        
        @type    tok: string
        @param    tok: nombre del token que el Nodo representa.
        
        @type    lex: string
        @param    lex: valor lexicografico representado por el Nodo.
        
        @type    ind: int
        @param    ind: numero de token segun el listado original de entrada.
        """
        self.token = tok
        self.lexema = lex
        self.indice = ind
    
    def __str__( self ):
        """
        Representacion grafica (caracteres) del Nodo actual (toString tipo 1).
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        """
        return "Nodo(" + self.token + ", " + self.lexema + ", " + str(self.indice) + ")"
        
    def __repr__(self):
        """
        Representacion grafica (caracteres) del Nodo actual (toString tipo 2).
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        """
        return "Nodo(" + self.token + ", " + self.lexema + ", " + str(self.indice) + ")"
        
    def getToken(self):
        """
        Obtiene el nombre del token representado por el Nodo actual.
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        """
        return self.token
    
    def setToken(self, tok):
        """
        Asigna el nombre del token representado por el Nodo actual.
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        
        @type    tok: string
        @param    tok: nombre del token que el Nodo representa.
        """
        self.token = tok
    
    def getLexema(self):
        """
        Obtiene el valor lexicografico del token representado por el Nodo actual.
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        """
        return self.lexema
    
    def setLexema(self, lex):
        """
        Asigna el valor lexicografico del token representado por el Nodo actual.
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        
        @type    lex: string
        @param    lex: valor lexicografico representado por el Nodo.
        """
        self.lexema = lex
    
    def getIndice(self):
        """
        Regresa el numeral del token (en el listado original de entrada) representado por el Nodo actual.
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        """
        return self.indice
    
    def setIndice(self, ind):
        """
        Asigna el numeral del token representado por el Nodo actual. Se interpreta como el equivalente a su indice en el listado original de entrada.
        @type    self: Nodo
        @param    self: referencia al objeto Nodo actual
        
        @type    ind: int
        @param    ind: numero de token segun el listado original de entrada.
        """
        self.indice = ind
        
class terminalProcessor:
    
    """
    Permite realizar la separacion entre los terminales y la gramatica propuesta. Provee los metodos necesarios para parsear el XML de terminales y construir los diccionarios de datos pertinentes para los analisis posteriores.
    @since: 4/14/2011
    @version: 1.0
    """
    
    dom = None
    """ ??? """
    
    def __init__(self, filename):
        """
        Constructor
        @type    self: terminalProcessor
        @param    self: referencia al objeto terminalProcessor actual
        
        @type    filename: string
        @param    filename: ??????
        """
        global dom
        fsock = open(filename)
        xmlText = fsock.read()
        fsock.close()
        xmlText = xmlText.replace("\n","")
        xmlText = xmlText.replace("\r","")
        xmlText = xmlText.replace("\t","")
        dom = parseString(xmlText)

    def getTerminals(self):
        """
        Obtiene los diccionarios creados segun el XML de terminales especificado. Diccionario de palabras, articulos y terminales en general.
        @type    self: terminalProcessor
        @param    self: referencia al objeto terminalProcessor actual
        """
        terminals = {}
        palabras = {}
        articulos = {}
        terminales = dom.getElementsByTagName('terminal')
        for terminal in terminales:
            for palabraEjecutable in terminal.childNodes:
                for sinonimo in palabraEjecutable.childNodes:
                    if not(sinonimo.localName in palabras.keys()):
                        palabras[sinonimo.localName] = palabraEjecutable.localName
                        articulos[sinonimo.localName] = sinonimo.getAttribute("genero")
                palabras[palabraEjecutable.localName] = palabraEjecutable.localName
                articulos[palabraEjecutable.localName] = palabraEjecutable.getAttribute("genero")
        for noTerminal in dom.getElementsByTagName('noTerminal'):
            name = str(noTerminal.attributes["name"].value).encode('latin-1')
            definition = ""
            i = 1
            for terminal in noTerminal.childNodes:
                sinons = ""
                for palabra in terminal.childNodes:
                    definition += "\'" + palabra.localName + "\'" + ' '
                    if (len(palabra.childNodes) > 0):
                        j = 1
                        for sinon in palabra.childNodes:
                            if (sinons.find("\'" + sinon.localName + "\'") < 0):
                                sinons += "\'" + sinon.localName + "\'"
                                if (j<len(palabra.childNodes)):
                                    sinons += '|'
                            j = j + 1
                            
                definition = definition.strip()
                if (len(sinons) > 0):
                    definition += '|' + sinons
                if (i<len(noTerminal.childNodes)):
                    definition += '|'
                i = i + 1
            definition = definition.encode('latin-1')
            terminals[name] = definition
        return [terminals, palabras, articulos]

class LogicoABJ:
    
    """
    Esta clase representa el controlador en el MVC del proyecto ABJ.
    @since: 4/14/2011
    @version: 1.0
    """
    
    _gramString = None
    """ Variable que contiene la gramatica generada a partir de los XML de terminales """
    
    _diccionario = None
    """ ??? """
    
    _keywords = None
    """ Listado de keywords """
    
    _sinonimos = None
    """ Diccionario de sinonimos. Terminal --> Terminal Generatriz """
    
    _genero = None
    """ Diccionario de generos. Terminal --> genero """
    
    _articulo = None
    """ Diccionario de articulos. ????????? """
    
    _gramatica = None
    """ Objeto del NLTK para contener la gramatica procesada. """
    
    _rd_parser = None
    """ Objeto del NLTK para representar el parser descendente de la gramatica generada. """
    
    _problema = None
    """ Objeto logico que representa el problema a correr. """
    
    _heroe = None
    """ Referencia al Heroe del problema """
    
    _direccion={"derecha":[1,0], "izquierda":[-1, 0], "adelante":[0, 1], "atras":[0, -1]}
    """ Direcciones basicas de movimiento """
    
    _longitud={"mucho":10, "poco":3, "todo":30}
    """ Interpretaciones basicas de cantidad """
    
    _logAction = 0
    """ Determina si se crea una entrada en el log luego de una iteracion (o recursion) de ejecucionSemantica """
    
    _errorMessage=""
    """ Contiene el mensaje de error que se despliega en el errorDialog"""
    
    # Gramática de intérprete y no de compilador
    def genIntGramaticaKeywords(self, term_rep):
        """
        Generador de la gramatica a partir de un archivo XML de entrada
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    term_rep: string
        @param    term_rep: URL relativa del archivo de terminales a leer
        """
        # Construir los terminales
        terminales = terminalProcessor(term_rep)
        retornado = terminales.getTerminals()
        terms = retornado[0]
        diccionario = retornado[1]
        self._diccionario = diccionario
        generos = retornado[2]
        
        # Calcular los keywords
        keyw = ""
        keyw = terms['vPlantear'] + terms['iCaller'] + terms['vScan'] + terms['vPresSubj'] + terms['arts'] 
        keyw = keyw + terms['sus'] + terms['preps'] + terms['vLigar'] + terms['vDligar'] + terms['vMov'] + terms['dirs'] + terms['longs']
        keyw = keyw + terms['hacer'] + terms['reps'] + terms['si'] + terms['sino'] + terms['vCambPostura']
        keyw = re.sub("'", " ", keyw)
        keyw = re.sub("\|", " ", keyw)
        keyw = keyw + " id num "
        keyw = keyw.split()
        
        # Obtener los primeros 4 articulos (fem, fems, masc, mascs)
        set_articulos = set()
        l = 0
        arts = terms['arts'].replace("'", "").split("|")
        while len(set_articulos) < 4:
            set_articulos.add(diccionario.get(arts[l]))
            l = l + 1
        
        # Construir antidiccionario (genero --> articulo base)
        self._articulo = {}
        for art in set_articulos:
            self._articulo[generos.get(art)] = art
        
        # Generar la gramatica (Español Interpretado 0.0.1)
        gString = """
            P -> PLA 'id' | PLA SUS | PAS
            PLA -> """ + terms['vPlantear'] + """
            PAS -> SCAN | LIG | DLIG | MOV | HACE | COND_P | CAMB_POSTURA
            SCAN -> V_SCAN """ + terms['iCaller'] + """ V_PRES_SUBJ | V_SCAN ART SUS | V_SCAN PREP ART SUS
            V_SCAN -> """ + terms['vScan'] + """
            V_PRES_SUBJ -> """ + terms['vPresSubj'] + """
            ART -> """ + terms['arts'] + """
            SUS -> """ + terms['sus'] + """
            PREP -> """ + terms['preps'] + """
            LIG -> V_LIG ART SUS | V_LIG ART SUS 'de' ART SUS | V_LIG ART SUS 'del' SUS
            CAMB_POSTURA -> V_CAMB_POSTURA PREP ART SUS | V_CAMB_POSTURA
            V_CAMB_POSTURA -> """ + terms['vCambPostura'] + """
            V_LIG -> """ + terms['vLigar'] + """
            DLIG -> V_DLIG ART SUS | V_DLIG ART SUS PREP ART SUS
            V_DLIG -> """ + terms['vDligar'] + """
            MOV -> V_MOV OBJETIVO
            V_MOV -> """ + terms['vMov'] + """
            OBJETIVO -> ART SUS | ART DIR LONG 
            DIR -> """ + terms['dirs'] + """ 
            LONG -> """ + terms['longs'] + """
            HACE -> VERBO ART SUS | VERBO ART SUS REP| VERBO
            VERBO -> """ + terms['hacer'] + """
            REP -> """ + terms['reps'] + """
            COND_P -> SI COND RES SI_NO RES
            RES -> PAS RES | PAS
            SI -> """ + terms['si'] + """
            SI_NO -> """ + terms['sino'] + """
            COND -> 'xO'
            """
        
        return gString, keyw, diccionario, generos

    def lexer(self, lexemas):
        """
        Generador de la gramatica
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    lexemas: list
        @param    lexemas: lista de strings que representan los valores lexicograficos de los tokens encontrados durante el analises.
        """
        # Arreglo de identificadores
        idents = range(len(lexemas))
        
        # Ciclo de busqueda de identificadores
        for i in range(len(idents)):
        
            # Verificar si es algun keyword
            if(self.matchKw(lexemas[i])):
                idents[i] = lexemas[i]
            else:
                idents[i] = self.matchRegEx(lexemas[i])
                
        return idents
        
    def parser(self, tokens):
        """
        Parser
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    tokens: list
        @param    tokens: lista de los nombres de los tokens encontrados en el analisis lexico
        """
        # Parsear
        try:
        
            arbolParse = self._rd_parser.nbest_parse(tokens)
            
            # No se genero el arbol del parse
            if len(arbolParse) == 0:
                return None
            else:
                return arbolParse
            
        except ValueError, e:
            
            # Imprimir error
            print "Token desconocido:"
            print e
            return None
         
    def ejecucionSemantica(self, subArbol, lexemas):
        """
        Metodo para verificar coherencia y ejecutar la instruccion solicitada
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    subArbol: Nodo
        @param    subArbol: Nodo padre del subarbol a analizar / ejecutar
        
        @type    lexemas: list
        @param    lexemas: listado de los valores lexicograficos encontrados de la entrada por el lexer.
        """
        sa_id = subArbol.node
        sa_len = len(subArbol)
        
        # Variables encontradas en cada instruccion
        id_problema = ""
        verbo_scan = ""
        articulo = ""
        sustantivo = ""
        accion_externa = ""
        accion_interna = ""
        prposicion = ""
        objetivo = [0,0]
        direccion = [0,0]
        longitud = 0
        veces = 0
        
        self._logAction = 0
        
        # P
        if sa_id == "P":
            
            # P -> PLA 'id' | PLA SUS
            if sa_len == 2:
                
                id_problema = ""
                
                try:
                    
                    # P -> PLA SUS
                    tmp = subArbol[1].node == "SUS"
                    id_problema = self.ejecucionSemantica(subArbol[1], lexemas)
                except AttributeError:
                    
            # P -> PLA 'id'
            #if sa_len == 2:
                    id_problema = subArbol[1].getLexema()
                
                try:
                    
                    # Algoritmo para cargar el problema
                    exec("self._problema = " + id_problema + "." + id_problema + "()")
                    
                    # Guardar en un temporal el nombre del heroe lógico
                    nombre_h = self._heroe.getNombre()
                    
                    # Cargar en el heroe lógico al héroe construido en el problema
                    # Cargado
                    self._heroe = self._problema.getHeroe()
                    
                    # Ajustar el nombre del héroe lógico
                    self._heroe.setNombre(nombre_h)
                    
                    print "\n (y) " + id_problema + " cargado exitosamente.\n"
                    
                except NameError, e:
                    
                    print "\n (!) Error: problema no encontrado.\n"
                    
            # P -> PAS
            elif sa_len == 1:
                if self.ejecucionSemantica(subArbol[0], lexemas) != None:
                    pass
                    #Regresar la escena para que se renderee
                    # print "\n (y) Comando ejecutado exitosamente " + id_problema + "\n"
        
        # PLA -> """ + terms['vPlantear'] + """
                
        # PAS -> SCAN | LIG | DLIG | MOV | HACE | COND_P
        elif sa_id == "PAS":
            
            # PAS -> SCAN
            # PAS -> LIG 
            # PAS -> DLIG 
            # PAS -> MOV 
            # PAS -> HACE 
            # PAS -> COND_P  
            return self.ejecucionSemantica(subArbol[0], lexemas)
            
        # SCAN
        elif sa_id == "SCAN":
            
            verbo_scan = self.ejecucionSemantica(subArbol[0], lexemas)
            
            # SCAN -> V_SCAN """ + terms['iCaller'] + """ V_PRES_SUBJ
            if isinstance(subArbol[1], Nodo):
                subj_buscar = self.ejecucionSemantica(subArbol[sa_len - 1], lexemas)
                
                # Propagar el error
                if subj_buscar == None:
                    return None
                
                # Algoritmo para mostrar lo encontrado
                # print "se desea buscar un objeto que pueda " + subj_buscar # <------------------------------------ MUESTRAS PARA EL DEBUG
            
            # SCAN -> V_SCAN ART SUS
            elif subArbol[1].node == "ART":
                articulo = self.ejecucionSemantica(subArbol[1], lexemas)
                sustantivo = self.ejecucionSemantica(subArbol[2], lexemas)
                
                # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                if self.comparaGenero(articulo, sustantivo):
                    # Algoritmo para mostrar lo encontrado
                    # print "se desea buscar " + articulo + " " + sustantivo 
                    pass
                else:
                    self.errorGenero(articulo, sustantivo)
                    return None
                
            # SCAN -> V_SCAN PREP ART SUS
            elif subArbol[1].node == "PREP":
                preposicion = self.ejecucionSemantica(subArbol[1], lexemas)
                articulo = self.ejecucionSemantica(subArbol[2], lexemas)
                sustantivo = self.ejecucionSemantica(subArbol[3], lexemas)
                objeto = self._problema.getObjeto(sustantivo)
                if (objeto.compararPosicion(self._heroe.getPosicion())):# or self._heroe.getPostura()==0):
                
                    # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                    if self.comparaGenero(articulo, sustantivo):
                            # Algoritmo para mostrar lo encontrado
                            # print "se desea buscar " + preposicion + " " + articulo + " " + sustantivo # <------------------ MUESTRASS PARA EL DEBUG
                            pass
                    else:
                            self.errorGenero(articulo, sustantivo)
                            return None
                else:
                    self._logAction = -1
                    # print "El heroe no ir a buscar a " + articulo + sustantivo + " si esta sentado" 
                    print "Estoy muy lejos de " + articulo + sustantivo
                
        # V_SCAN -> """ + terms['vScan'] + """
        # V_PRES_SUBJ -> """ + terms['vPresSubj'] + """
        # ART -> """ + terms['arts'] + """
        # SUS -> """ + terms['sus'] + """
        # PREP -> """ + terms['preps'] + """
        # V_LIG -> """ + terms['vLigar'] + """
        # V_DLIG -> """ + terms['vDligar'] + """ 
        # V_MOV -> """ + terms['vMov'] + """
        # VERBO -> """ + terms['hacer'] + """
        elif sa_id in ["V_SCAN","V_PRES_SUBJ","ART","SUS","PREP","V_LIG", "V_DLIG","V_MOV", "VERBO"]:
            return subArbol[0].getLexema()
            
        # LIG
        elif sa_id == "LIG":
            # LIG -> V_LIG ART SUS 
            if sa_len == 3:
                accion_interna = self.ejecucionSemantica(subArbol[0], lexemas)
                articulo = self.ejecucionSemantica(subArbol[1], lexemas)
                sustantivo = self.ejecucionSemantica(subArbol[2], lexemas)
                objeto = self._problema.getObjeto(sustantivo)
                if (objeto.compararPosicion(self._heroe.getPosicion())):
                    #distancia = math.hypot(objeto.getX()-self._heroe.getX(),objeto.getY()-self._heroe.getY())
                    #print str(distancia)+" "+str(objeto.getPosicion())+" "+str(self._heroe.getPosicion())
                    # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                    if self.comparaGenero(articulo, sustantivo):
                        # Algoritmo para ejecutar la ligadura
                        # print "se desea ligar al heroe " + articulo + " " + sustantivo
                        #self._problema.getHeroe().pushObjeto(self._problema.getObjeto(sustantivo))
                        #self._heroe.pushObjeto(objeto)
                        #self._problema.getObjeto(sustantivo).ocultar()
                        #objeto.ocultar()
                        #print sustantivo, self._problema.getObjeto(sustantivo).esVisible() 
                        #print self._problema.getHeroe().getElementos()
                        #if distancia<=50.0:
                        #    self._heroe.tener(objeto)
                        #if (objeto.compararPosicion(self._heroe.getPosicion())):# or self._heroe.getPostura()==0):
    #                    if (self._heroe.getPosicion() == objeto.getPosicion()):    
                        #self._heroe.setPosicion(objeto.getPosicion())
                        # Quitar al objeto de su contenedor
                        objetos_p = self._problema.getObjetos()
                        for o in objetos_p:
                            if isinstance(o, ITener):
                                if objeto in o.getObjetos():
                                    #print "ANTES", self._problema.getObjetos()
                                    break
                                else:
                                    o=None
                            else:
                                o=None       
                        # El heroe logro agarrar el objeto? 
                        try:
							#sys.stdout = sys.stderr
							
							if self._heroe.tener(objeto)==None:
								
								self._logAction = -1
								
							else:
                                #El contenedor debe tirar el objeto
								try:
									o.soltar(objeto.getNombre())
								except    AttributeError, e:
									pass
                        except Exception as msg:
    						self._logAction = -1
    						print msg
                        
                        # print "\nahora el heroe tiene "
                        for obj in self._heroe.getObjetos():
                            # print obj.getNombre()
    #                    else:
    #                        self._logAction = -1
    #                        # print "El heroe no puede ir hacia " + articulo + sustantivo +" si esta " + self._heroe.getPosturaString()
    #                        print "El heroe no esta cerca de " + articulo + " " + sustantivo
                            pass
                    else:
                        self.errorGenero(articulo, sustantivo)
                        return None
                else:
                        self._logAction = -1
                        # print "El heroe no se puede mover hacia la " + OI + " si esta " + self._heroe.getPosturaString()
                        print "Estoy muy lejos de " + sustantivo
            #V_LIG ART SUS 'de' 'la' SUS
            elif sa_len == 6:
                accion_interna = self.ejecucionSemantica(subArbol[0], lexemas)
                articulo_OD = self.ejecucionSemantica(subArbol[1], lexemas)
                OD = self.ejecucionSemantica(subArbol[2], lexemas)
                OI = self.ejecucionSemantica(subArbol[5], lexemas)
                dador = self._problema.getObjeto(OI)
                objeto = self._problema.getObjeto(OD)
                                
                if (dador.compararPosicion(self._heroe.getPosicion())):# or self._heroe.getPostura()==0):
                    # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                    if self.comparaGenero(articulo_OD, OD):
                        if self.comparaGenero('la', OI):
                            # Algoritmo para ejecutar la ligadura
                            # print "se desea ligar al heroe " + articulo_OD + " " + OD + " que está en la " + OI
                            # self._heroe.setPosicion(dador.getPosicion())
                            dador.soltar(OD)
                            try:
                                self._heroe.tener(objeto)
                            except Exception as msg:
                                self._logAction = -1
                                print msg
                            # print "\nahora el heroe tiene "
                            for obj in self._heroe.getObjetos():
                                # print obj.getNombre()
                                pass
                            # print "\ny la " + OI + " tiene "
                            for obj in dador.getObjetos():
                                # print obj.getNombre()
                                pass
                        else:
                            self.errorGenero('la', OI)
                            return None
                    else:
                        self.errorGenero(articulo_OD, OD)
                        return None
                else:
                    self._logAction = -1
                    # print "El heroe no se puede mover hacia la " + OI + " si esta " + self._heroe.getPosturaString()
                    print "Estoy muy lejos de la " + OI
            #V_LIG ART SUS 'del' SUS
            elif sa_len == 5:
                accion_interna = self.ejecucionSemantica(subArbol[0], lexemas)
                articulo_OD = self.ejecucionSemantica(subArbol[1], lexemas)
                OD = self.ejecucionSemantica(subArbol[2], lexemas)
                OI = self.ejecucionSemantica(subArbol[5], lexemas)
                dador = self._problema.getObjeto(OI)
                objeto = self._problema.getObjeto(OD)
                                
                if (dador.compararPosicion(self._heroe.getPosicion())):# or self._heroe.getPostura()==0):
                    # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                    if self.comparaGenero(articulo_OD, OD):
                        if self.comparaGenero('el', OI):
                            # Algoritmo para ejecutar la ligadura
                            # print "se desea ligar al heroe " + articulo_OD + " " + OD + " que está en el " + OI
                            #self._heroe.setPosicion(dador.getPosicion())
                            dador.soltar(OD)
                            try:
                                self._heroe.tener(objeto)
                            except Exception as msg:
                                self._logAction = -1
                                print msg
                            # print "\nahora el heroe tiene "
                            for obj in self._heroe.getObjetos():
                                # print obj.getNombre()
                                pass
                            # print "\ny el " + OI + " tiene "
                            for obj in dador.getObjetos():
                               # print obj.getNombre()
                               pass
                        else:
                            self.errorGenero('la', OI)
                            return None
                    else:
                        self.errorGenero(articulo_OD, OD)
                        return None
                else:
                    self._logAction = -1
                    # print "El heroe no se puede mover hacia el" + OI + " si esta " + self._heroe.getPosturaString()
                    print "Estoy muy lejos del " + OI
        
        # CAMB_POSTURA -> V_CAMB_POSTURA PREP ART SUS | V_CAMB_POSTURA
        elif sa_id == "CAMB_POSTURA":
            # CAMB_POSTURA -> V_CAMB_POSTURA
            if sa_len == 1:
                accion_interna = self.ejecucionSemantica(subArbol[0], lexemas)
                
                if (accion_interna == "sentarse") or (accion_interna == "siento") or (accion_interna == "sienta"):
                    self._heroe.setPostura(1)
                    # print "El heroe se ha sentado"
                elif (accion_interna == "pararse") or (accion_interna == "paro") or (accion_interna == "para"):
                    self._heroe.setPostura(0)
                    # print "El heroe se ha parado"
                    
            # CAMB_POSTURA -> V_CAMB_POSTURA PREP ART SUS
            elif sa_len == 4:
                accion_interna = self.ejecucionSemantica(subArbol[0], lexemas)
                
        elif sa_id == "V_CAMB_POSTURA":
            if len(subArbol)>1:
                return subArbol[1].getLexema()
            else:
                return subArbol[0].getLexema()
        # DLIG
        elif sa_id == "DLIG":
            
            #DLIG -> V_DLIG ART SUS
            if sa_len == 3:
                accion_interna = self.ejecucionSemantica(subArbol[0], lexemas)
                articulo = self.ejecucionSemantica(subArbol[1], lexemas)
                sustantivo = self.ejecucionSemantica(subArbol[2], lexemas)
                objeto = self._problema.getHeroe().getObjeto(sustantivo)
                
                # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                if self.comparaGenero(articulo, sustantivo):
                    # Algoritmo para ejecutar la "desligadura"
                    # print "se desea desligar del heroe " + articulo + " " + sustantivo # <---------------------------- MUESTRAS PARA EL DEBUG
                    self._heroe.soltar(sustantivo)
                    objeto.setPosicion(self._heroe.getPosicion())
                    # print "\nahora el heroe tiene "
                    for obj in self._heroe.getObjetos():
                       # print obj.getNombre()
                       pass
                else:
                    self.errorGenero(articulo, sustantivo)
                    return None
            #DLIG -> V_DLIG ART SUS PREP ART SUS
            elif sa_len == 6:
                accion_interna = self.ejecucionSemantica(subArbol[0], lexemas)
                articulo_OD = self.ejecucionSemantica(subArbol[1], lexemas)
                OD = self.ejecucionSemantica(subArbol[2], lexemas)
                preposicion = self.ejecucionSemantica(subArbol[3], lexemas)
                articulo_OI = self.ejecucionSemantica(subArbol[4], lexemas)
                OI = self.ejecucionSemantica(subArbol[5], lexemas)
                receptor = self._problema.getObjeto(OI)
                
                objeto=None
                
                if(accion_interna=='vertir'):
                    objeto =self._problema.getObjeto(OD)
                else:
                    objeto = self._problema.getHeroe().getObjeto(OD)
                    
                
                if (receptor.compararPosicion(self._heroe.getPosicion())):# or self._heroe.getPostura()==0):
                    if self.comparaGenero(articulo_OD, OD):
                        if self.comparaGenero(articulo_OI, OI):
                            
                            if(accion_interna=='vertir'):
                                if(isinstance(receptor, ITenerParticula)):
                                    objeto.vertir(receptor)
                                else:
                                    self._logAction = -1
                                    # print "El heroe no se puede mover hacia " + articulo_OI + OI + " si esta " + self._heroe.getPosturaString()
                                    print "Cuidado no puedes vertir ", articulo_OD, OD, "en", articulo_OI, OI, "\n porque no podras utilizarlo(a) despues."
                            else:
                                # Algoritmo para ejecutar la "desligadura"
                               # print "se desea desligar al heroe de " + articulo_OD + " " + OD + " y ligar eso a " + articulo_OI + " " + OI# <---------------------------- MUESTRAS PARA EL DEBUG
                                # self._heroe.setPosicion(receptor.getPosicion())
                                try:
                                    receptor.tener(objeto)
                                    self._heroe.soltar(OD)
                                except Exception as msg:
                                    self._logAction = -1
                                    print msg
                                # print "\nahora el heroe tiene "
                                for obj in self._heroe.getObjetos():
                                    # print obj.getNombre()
                                    pass
                                # print "\ny " + articulo_OI + " " + OI + " tiene "
                                for obj in receptor.getObjetos():
                                    # print obj.getNombre()
                                    pass
                        else:
                            self.errorGenero(articulo_OI, OI)
                            return None
                    else:
                        self.errorGenero(articulo_OD, OD)
                        return None
                else:
                    self._logAction = -1
                    # print "El heroe no se puede mover hacia " + articulo_OI + OI + " si esta " + self._heroe.getPosturaString()
                    print "Estoy muy lejos de " + articulo_OI + " " + OI
                
        # MOV -> V_MOV OBJETIVO 
        elif sa_id == "MOV":
            if (self._heroe.getPostura()==0):
                accion_interna = self.ejecucionSemantica(subArbol[0], lexemas)
                objetivo = self.ejecucionSemantica(subArbol[1], lexemas)
                
                # Propagar el error
                if objetivo == None:
                    return None
                
                # Algoritmo para moverse
                self._problema.getHeroe().setPosicion(objetivo)
                # print self._problema.getHeroe().getPosicion()
                #print "se desea moverse a las coordenadas (" + str(objetivo[0]) + ", " + str(objetivo[1]) + ")" # <--- MUESTRAS PARA EL DEBUG
            else:
                self._logAction = -1
                print "El heroe no se puede mover si esta " + self._heroe.getPosturaString()
            
        # OBJETIVO
        elif sa_id == "OBJETIVO":
            
            # OBJETIVO -> ART SUS
            if sa_len == 2:
                articulo = self.ejecucionSemantica(subArbol[0], lexemas)
                sustantivo = self.ejecucionSemantica(subArbol[1], lexemas)
                
                # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                if self.comparaGenero(articulo, sustantivo):
                    # Algoritmo para determinar la posicion del objeto al cual dirigirnos
                    #Busca el objeto en la escena
                    
                    objeto=self._problema.getObjeto(sustantivo)
                    
                    #Existe el objeto?
                    if objeto == None:
                        return None
                    else:
                        return objeto.getPosicion()
                        
                else:
                    self.errorGenero(articulo, sustantivo)
                    return None
            
            # OBJETIVO -> ART DIR LONG  
            elif sa_len == 3:
                articulo = self.ejecucionSemantica(subArbol[0], lexemas)
                direccion = self.ejecucionSemantica(subArbol[1], lexemas)
                longitud = self.ejecucionSemantica(subArbol[2], lexemas)
                
                # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                #if self.comparaGenero(articulo, sustantivo):
                # Algoritmo para determinar la posicion del objeto al cual dirigirnos
                posicion=self._problema.getHeroe().getPosicion()
                self._problema.getHeroe().setPosicion([(posicion[0]+longitud*direccion[0]), (posicion[1]+longitud*direccion[1])])
                return  self._problema.getHeroe().getPosicion()  # <----------------------------------------------------------------------------- MUESTRAS PARA EL DEBUG
                #else:
                #   self.errorGenero(articulo, sustantivo)
                #   return None
                
        # DIR -> """ + terms['dirs'] + """ 
        elif sa_id == "DIR":
            
            # Algoritmo para determinar la direccion con 
            # la que debemos movernos
            return self._direccion[subArbol[0].getLexema()] # <------------------------------------------------------------------------------------- MUESTRAS PARA EL DEBUG
            
        # LONG -> """ + terms['longs'] + """
        elif sa_id == "LONG":
            
            # Algoritmo para determinar que tanto nos 
            # vamos a mover
                        if subArbol[0].getToken()=="num":
                                return int(subArbol[0].getLexema())
                        else:
                                return self._longitud[subArbol[0].getLexema()]
            
        
        # HACE 
        elif sa_id == "HACE":
            
            accion_externa = self.ejecucionSemantica(subArbol[0], lexemas)
            
            # HACE -> VERBO
            if sa_len == 1: 
                
                # Algoritmo para ejecutar la acción
                # print "se desea que el heroe haga: " + accion_externa # <----- MUESTRASS PARA EL DEBUG
                pass
                
            else:
                
                articulo = self.ejecucionSemantica(subArbol[1], lexemas)
                sustantivo = self.ejecucionSemantica(subArbol[2], lexemas)
                
                # Corroborar que se escribe de forma correcta la formula articulo sustantivo
                if not self.comparaGenero(articulo, sustantivo):
                    self.errorGenero(articulo, sustantivo)
                    return None
                
                # HACE -> VERBO ART SUS
                if sa_len == 3: 
                    # Algoritmo para ejecutar la acción
                    #sustantivo = self.ejecucionSemantica(subArbol[2], lexemas)
                    #articulo = self.ejecucionSemantica(subArbol[1], lexemas)
                    objeto = self._problema.getObjeto(sustantivo)
                    if objeto.compararPosicion(self._heroe.getPosicion()):
                        # print "se desea que el heroe haga: " + accion_externa + " " + articulo + " " + sustantivo # <----- MUESTRASS PARA EL DEBUG
                        self._problema.setPropiedad(sustantivo, accion_externa, '')
                        # print "<" + accion_externa + "> finalizado"
                    else:
                        self._logAction = -1
                        print "Estoy muy lejos de " + articulo + " " + sustantivo
                    
                # HACE -> VERBO ART SUS REP 
                elif sa_len == 4:
                    objeto = self._problema.getObjeto(sustantivo)
                    accion = self._diccionario[accion_externa]
                    veces = self.ejecucionSemantica(subArbol[3], lexemas)
                    #self._problema.setPropiedad(sustantivo, accion_externa, veces)
                    
                    # Algoritmo para ejecutar la acción un número de veces
                    # print "se desea que el heroe haga: " + accion_externa + " " + articulo + " " + sustantivo # <----- MUESTRASS PARA EL DEBUG
                    # print str(veces) + " veces"
                
                    for i in range(1,veces):
                        self._problema.setPropiedad(sustantivo, accion, '')
                    # print "<" + accion + "> " + str(veces) + " veces finalizado"
        # REP -> """ + terms['reps'] + """
        elif sa_id == "REP":
            
            # Algoritmo para calcular la cantidad de veces que una acción
            # externa se repetirá
            return 5 # <------------------------------------------------------------------------------------------- MUESTRASS PARA EL DEBUG
            
        # COND_P -> SI COND RES SI_NO RES
        elif sa_id == "COND_P":
            # print ""
            pass
        # SI -> """ + terms['si'] + """
        elif sa_id == "SI":
            # print ""
            pass
        # SI_NO -> """ + terms['sino'] + """
        elif sa_id == "SI_NO":
            # print ""
            pass
        #   
        elif sa_id == "COND":
            # print ""
            pass
        return self._logAction
    
    def matchRegEx(self, str):
        """
        Regresa el nombre del regex con el cual hay match
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    str: string
        @param    str: valor a comparar contra el conjunto de expresiones regulares.
        """
        matchObj = re.match( r'[a-z]([a-z 0-9 _]*)', str)
        
        if matchObj:
            return "id"
        
        matchObj = re.match( r'[0-9]([0-9]*)', str)
        
        if matchObj:
            return "num"
        
        return "err"

    def matchKw(self, str):
        """
        Verifica si str es un keyword
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    str: string
        @param    str: valor a comparar contra el conjunto de keywords.
        """
        for i in range(len(self._keywords)):
            if str == self._keywords[i]:
                return True
        return False

    def nodificar(self, subArbol, lexemas, siguiente_indice):
        """
        Hace un recorrido enOrden sobre el arbol para cambiar terminales (str) por Nodos
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    subArbol: Nodo
        @param    subArbol: Nodo padre del subarbol a nodificar
        
        @type    lexemas: list
        @param    lexemas: listado de los valores lexicograficos encontrados de la entrada por el lexer.
        
        @type    siguiente_indice: int
        @param    siguiente_indice: valor numerico a asignar al siguiente Nodo (posicion en el listado de tokens de la entrada original)
        """
        # No debo dejar que en un paso recursivo mande un str de parámetro
        sa_len = len(subArbol)
        
        # Para cada nodo hijo (subarbol)
        for i in range(sa_len):
            
            # Si el subarbol actual es del tipo str
            if isinstance(subArbol[i], str):
                
                # Caso base:
                # Convertir el str en un Nodo
                nu_nodo = Nodo(subArbol[i], lexemas[siguiente_indice], siguiente_indice)
                subArbol[i] = nu_nodo
                siguiente_indice = siguiente_indice + 1
                
            else:
            
                # Paso recursivo
                siguiente_indice = self.nodificar(subArbol[i], lexemas, siguiente_indice)
                
        return siguiente_indice
    
    def comparaGenero(self, comparando1, comparando2):
        """
        Regresa True si ambos comparandos poseen el mismo genero, False en caso contrario
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    comparando1: string
        @param    comparando1: string ya sea terminal o token
        
        @type    comparando2: string
        @param    comparando2: string ya sea terminal o token
        """
        # Terminar y genero neutro
        ter_num = "num"
        gen_num = self._genero.get(ter_num)
        
        # Verificar si alguno de los comparandos es un numero
        nuc1 = self.matchRegEx(comparando1)
        nuc2 = self.matchRegEx(comparando2)
        
        # Si es así, cambiar el número por el terminal que denota números
        if nuc1 == ter_num:
            comparando1 = nuc1
        if nuc2 == ter_num:
            comparando2 = nuc2
            
        # Obtener género
        gen1 = self._genero.get(comparando1)
        
        # Si el primer género es neutro
        if gen1 == gen_num:
            return True
        else:
            gen2 = self._genero.get(comparando2)
            
            # Si el segundo género es neutro
            if gen2 == gen_num:
                return True
                
            # Si los dos géneros son iguales
            return gen1 == gen2
    
    def errorGenero(self, articulo, sustantivo):
        """
        Devuelve el enunciado del error de genero entre articulo y sustantivo
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    articulo: string
        @param    articulo: articulo a comparar (articulo en el sentido gramatical: el la los las, etc)
        
        @type    sustantivo: string
        @param    sustantivo: sustantivo a comparar contra articulo
        """
        print "\n (!) El genero del articulo " + articulo.upper() + " no coincide con el del sustantivo " + sustantivo.upper() + "\n"
    
    def runCommand(self, str_command):
        """
        Metodo de comunicación entre la parte lógica y gráfica
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    str_command: string
        @param    str_command: representacion en lenguaje ABJ del comando a ejecutar.
        """
       
        #Abrir accion.txt
        saveout = sys.stdout
        fsock = open("accion.txt",'w')
        sys.stdout = fsock
        
        # Siempre que no se diga lo contrario, genere log entry
        self._logAction = 1
        # Minúsculas
        str_command = str_command.lower()
        
        # Split (calcular lexemas)
        lexemas = str_command.split()
    
        # Calcular identificadores de lexemas
        tokens = self.lexer(lexemas)
    
        # Calcular el arbol de parse de la entrada
        arbolDeParse = self.parser(tokens)
        
        if(arbolDeParse != None):
            
            # Cambiar strings de los terminales en objetos Nodo
            self.nodificar(arbolDeParse[0], lexemas, 0)
            self.ejecucionSemantica(arbolDeParse[0], lexemas)
            
        else:
            print "\n (!) Parser fallo al intentar generar el arbol: verifique la entrada.\n"
       
        #Cerrar accion.txt
        sys.stdout = saveout
        fsock.close()
        
        #Obtener texto del archivo
        fop = open("accion.txt",'r')
        self._errorMessage= fop.read()        
        fop.close()
        
        
        
        
    def __init__(self, terminales, nombre_heroe):
        """
        Constructor
        @type    self: LogicoABJ
        @param    self: referencia al objeto LogicoABJ actual
        
        @type    terminales: string
        @param    terminales: URL relativa del XML de terminales a usar en la ejecucion del programa
        
        @type    nombre_heroe: string
        @param    nombre_heroe: nombre del Heroe, para desplegar en un apartado posteriormente.
        """
        # Construccion de la gramatica, tabla de keywords y el parser
        self._gramString, self._keywords, self._sinonimos, self._genero = self.genIntGramaticaKeywords(terminales)
        self._gramatica = nltk.parse_cfg(self._gramString)
        self._rd_parser = nltk.RecursiveDescentParser(self._gramatica)
        
        # Inicialización del problema
        self._problema = None
        
        # Inicialización del héroe
        self._heroe = Heroe.Heroe(nombre_heroe)
